package system.memory;

import cpu.components.CacheUnit;
import cpu.components.MemoryUnit;
import cpu.datastores.CacheLine;
import cpu.datastores.Register16;
import cpu.datatypes.Byte;
import cpu.interfaces.Memory;
import cpu.datatypes.Word;

public class Cache implements Memory {
	
	private MemoryUnit memorycontroller;
	private CacheUnit cachecontroller;
	private static final int banks = 8;
	private CacheLine[]cachearray=new CacheLine[banks];

	public Cache( CacheUnit controller,MemoryUnit memoryunit ) {
		for (int bank =0;bank<banks;bank++)
		{			
			cachearray[bank]=new CacheLine();
			cachearray[bank].dirtybit=true;
			cachearray[bank].baseline=new Register16();
			
		}
		
		this.cachecontroller = controller;
		this.memorycontroller=memoryunit;
	}
	public void get( ) {
	int add=cachecontroller.MAR.toSignedInteger( );
	int blocknumber=add/16;
	int selected=blocknumber%8;
	int baseline;
	/// for more info about the design http://www.cs.ucr.edu/~junyang/teach/161_W06/slides/L15-cache2.pdf
	baseline=cachearray[selected].baseline.toSignedInteger();
	int offset=add-baseline;
	if(offset< 16 && offset>=0 &&!cachearray[selected].dirtybit)//hit
	{
		memorycontroller.MBR.byteLow.fromByte(cachearray[selected].get( offset ));
		//if (offset+1<16)
	    memorycontroller.MBR.byteHigh.fromByte( cachearray[selected].get( offset+1 ));
	    
	}
	
	
	else //miss
	{ cachearray[selected].baseline.fromRegister(cachecontroller.MAR);
	  int base=cachearray[selected].baseline.toSignedInteger();
		for(int i=0;i<16;i+=2)
		{
			memorycontroller.MAR.fromSignedInteger(base+i);
			memorycontroller.caching=false;
			memorycontroller.get();
			memorycontroller.caching=true;
			cachearray[selected].put(base+i,memorycontroller.MBR);
		}
		cachearray[selected].dirtybit=false;
		
		memorycontroller.MAR.fromSignedInteger(base);
		memorycontroller.MBR.byteLow.fromByte(cachearray[selected].get(0));
		memorycontroller.MBR.byteHigh.fromByte(cachearray[selected].get(1));
		
	}	                                                                                                                               
	// controller.MBR <- Memory(controller.MAR)
}
	public void put( ) {
		int add=cachecontroller.MAR.toSignedInteger();
		int blocknumber=add/16;
		int selected=blocknumber%8;
		int baseline;
		baseline=cachearray[selected].baseline.toSignedInteger();
		int offset=add-baseline;
		if(offset< 16 && offset>=0)//hit
		{
			cachearray[selected].put(offset+baseline,cachecontroller.MBR);
			memorycontroller.caching=false;
			memorycontroller.MAR.fromRegister(cachecontroller.MAR);
			memorycontroller.MBR.fromRegister(cachecontroller.MBR);
			memorycontroller.put();
			memorycontroller.caching=true;
		}
		else //miss
		{ 
			memorycontroller.caching=false;
			memorycontroller.MAR.fromRegister(cachecontroller.MAR);
			memorycontroller.MBR.fromRegister(cachecontroller.MBR);
			memorycontroller.put();
			memorycontroller.caching=true;
			//memorycontroller.MAR.fromRegister(cachecontroller.MAR);
		}
		
	}
}
